/* 返回true如果字符c是给定数组类型的分隔符 */

#define POSTGRES_ECPG_INTERNAL
#include "postgres_fe.h"

#include <math.h>

#include "ecpgerrno.h"
#include "ecpglib.h"
#include "ecpglib_extern.h"
#include "ecpgtype.h"
#include "pgtypes_date.h"
#include "pgtypes_interval.h"
#include "pgtypes_numeric.h"
#include "pgtypes_timestamp.h"
#include "sqlca.h"

/* 返回true如果字符c标记了给定数组类型的边界 */
static bool fc_array_delimiter(enum ARRAY_TYPE fc_isarray, char fc_c)
{
	if (fc_isarray == ECPG_ARRAY_ARRAY && fc_c == ',')
		return true;

	if (fc_isarray == ECPG_ARRAY_VECTOR && fc_c == ' ')
		return true;

	return false;
}

/* 返回true如果在扫描的字符串末尾发现了一些垃圾 */
static bool fc_array_boundary(enum ARRAY_TYPE fc_isarray, char fc_c)
{
	if (fc_isarray == ECPG_ARRAY_ARRAY && fc_c == '}')
		return true;

	if (fc_isarray == ECPG_ARRAY_VECTOR && fc_c == '\0')
		return true;

	return false;
}

/*
	 * INFORMIX允许将数字选择为int，结果是
	 * 被截断
	 */
static bool fc_garbage_left(enum ARRAY_TYPE fc_isarray, char **fc_scan_length, enum COMPAT_MODE fc_compat)
{
	/* 跳过无效字符 */
	if (fc_isarray == ECPG_ARRAY_NONE)
	{
		if (INFORMIX_MODE(fc_compat) && **fc_scan_length == '.')
		{
			/* 从src/backend/utils/adt/float.c窃取的代码 */
			do
			{
				(*fc_scan_length)++;
			} while (isdigit((unsigned char) **fc_scan_length));
		}

		if (**fc_scan_length != ' ' && **fc_scan_length != '\0')
			return true;
	}
	else if (ECPG_IS_ARRAY(fc_isarray) && !fc_array_delimiter(fc_isarray, **fc_scan_length) && !fc_array_boundary(fc_isarray, **fc_scan_length))
		return true;

	return false;
}

/* (double) NAN在某些NetBSD/MIPS版本上不起作用 */
#if defined(WIN32) && !defined(NAN)
static const uint32 nan[2] = {0xffffffff, 0x7fffffff};

#define NAN (*(const double *) nan)
#endif

static double fc_get_float8_infinity(void)
{
#ifdef INFINITY
	return (double) INFINITY;
#else
	return (double) (HUGE_VAL * HUGE_VAL);
#endif
}

static double fc_get_float8_nan(void)
{
	/* 从src/backend/utils/adt/encode.c导入 */
#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
	return (double) NAN;
#else
	return (double) (0.0 / 0.0);
#endif
}

static bool fc_check_special_value(char *fc_ptr, double *fc_retval, char **fc_endptr)
{
	if (pg_strncasecmp(fc_ptr, "NaN", 3) == 0)
	{
		*fc_retval = fc_get_float8_nan();
		*fc_endptr = fc_ptr + 3;
		return true;
	}
	else if (pg_strncasecmp(fc_ptr, "Infinity", 8) == 0)
	{
		*fc_retval = fc_get_float8_infinity();
		*fc_endptr = fc_ptr + 8;
		return true;
	}
	else if (pg_strncasecmp(fc_ptr, "-Infinity", 9) == 0)
	{
		*fc_retval = -fc_get_float8_infinity();
		*fc_endptr = fc_ptr + 9;
		return true;
	}

	return false;
}

/*
	 * 如果我们正在执行回归测试，则不要记录偏移量变量，
	 * 它依赖于机器的对齐方式。
	 */

unsigned ecpg_hex_enc_len(unsigned fc_srclen)
{
	return fc_srclen << 1;
}

unsigned ecpg_hex_dec_len(unsigned fc_srclen)
{
	return fc_srclen >> 1;
}

static inline char fc_get_hex(char fc_c)
{
	static const int8 fc_hexlookup[128] = {
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
		-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
		-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
	};
	int			fc_res = -1;

	if (fc_c > 0 && fc_c < 127)
		fc_res = fc_hexlookup[(unsigned char) fc_c];

	return (char) fc_res;
}

static unsigned fc_hex_decode(const char *fc_src, unsigned fc_len, char *fc_dst)
{
	const char *fc_s,
			   *fc_srcend;
	char		fc_v1,
				fc_v2,
			   *fc_p;

	fc_srcend = fc_src + fc_len;
	fc_s = fc_src;
	fc_p = fc_dst;
	while (fc_s < fc_srcend)
	{
		if (*fc_s == ' ' || *fc_s == '\n' || *fc_s == '\t' || *fc_s == '\r')
		{
			fc_s++;
			continue;
		}
		fc_v1 = fc_get_hex(*fc_s++) << 4;
		if (fc_s >= fc_srcend)
			return -1;

		fc_v2 = fc_get_hex(*fc_s++);
		*fc_p++ = fc_v1 | fc_v2;
	}

	return fc_p - fc_dst;
}

unsigned ecpg_hex_encode(const char *fc_src, unsigned fc_len, char *fc_dst)
{
	static const char fc_hextbl[] = "0123456789abcdef";
	const char *fc_end = fc_src + fc_len;

	while (fc_src < fc_end)
	{
		*fc_dst++ = fc_hextbl[(*fc_src >> 4) & 0xF];
		*fc_dst++ = fc_hextbl[*fc_src & 0xF];
		fc_src++;
	}
	return fc_len * 2;
}

bool ecpg_get_data(const PGresult *fc_results, int fc_act_tuple, int fc_act_field, int fc_lineno,
			  enum ECPGttype fc_type, enum ECPGttype fc_ind_type,
			  char *fc_var, char *fc_ind, long fc_varcharsize, long fc_offset,
			  long fc_ind_offset, enum ARRAY_TYPE fc_isarray, enum COMPAT_MODE fc_compat, bool fc_force_indicator)
{
	struct sqlca_t *fc_sqlca = ECPGget_sqlca();
	char	   *fc_pval = (char *) PQgetvalue(fc_results, fc_act_tuple, fc_act_field);
	int			fc_binary = PQfformat(fc_results, fc_act_field);
	int			fc_size = PQgetlength(fc_results, fc_act_tuple, fc_act_field);
	int			fc_value_for_indicator = 0;
	long		fc_log_offset;

	if (fc_sqlca == NULL)
	{
		ecpg_raise(fc_lineno, ECPG_OUT_OF_MEMORY,
				   ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
		return false;
	}

	/* pval是一个指向值的指针 */
	if (ecpg_internal_regression_mode)
		fc_log_offset = -1;
	else
		fc_log_offset = fc_offset;

	ecpg_log("ecpg_get_data on line %d: RESULT: %s offset: %ld; array: %s\n", fc_lineno, fc_pval ? (fc_binary ? "BINARY" : fc_pval) : "EMPTY", fc_log_offset, ECPG_IS_ARRAY(fc_isarray) ? "yes" : "no");

	/*
		 * 这永远不应该发生，因为我们已经检查到至少找到
		 * 一个元组，但让我们安全起见。
		 */
	if (!fc_pval)
	{
		/* 我们将需要解码该值 */
		ecpg_raise(fc_lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
		return false;
	}

	/*
	 * 检查空值并相应地设置指示符，即-1如果为NULL而
	 * 0如果不为NULL
	 */

	/*
					 * Informix有另一种指定NULL的方式，注意
					 * 这使用特殊值表示NULL
					 */
	if (PQgetisnull(fc_results, fc_act_tuple, fc_act_field))
		fc_value_for_indicator = -1;

	switch (fc_ind_type)
	{
		case ECPGt_short:
		case ECPGt_unsigned_short:
			*((short *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_value_for_indicator;
			break;
		case ECPGt_int:
		case ECPGt_unsigned_int:
			*((int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_value_for_indicator;
			break;
		case ECPGt_long:
		case ECPGt_unsigned_long:
			*((long *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_value_for_indicator;
			break;
		case ECPGt_long_long:
		case ECPGt_unsigned_long_long:
			*((long long int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_value_for_indicator;
			break;
		case ECPGt_NO_INDICATOR:
			if (fc_value_for_indicator == -1)
			{
				if (fc_force_indicator == false)
				{
					/* 让我们检查它是否真的应该是数组 */
					ECPGset_noind_null(fc_type, fc_var + fc_offset * fc_act_tuple);
				}
				else
				{
					ecpg_raise(fc_lineno, ECPG_MISSING_INDICATOR,
							   ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER,
							   NULL);
					return false;
				}
			}
			break;
		default:
			ecpg_raise(fc_lineno, ECPG_UNSUPPORTED,
					   ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
					   ecpg_type_name(fc_ind_type));
			return false;
			break;
	}

	if (fc_value_for_indicator == -1)
		return true;

	/* 截断 */
	if (fc_isarray == ECPG_ARRAY_ARRAY)
	{
		if (*fc_pval != '{')
		{
			ecpg_raise(fc_lineno, ECPG_DATA_NOT_ARRAY,
					   ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
			return false;
		}

		switch (fc_type)
		{
			case ECPGt_char:
			case ECPGt_unsigned_char:
			case ECPGt_varchar:
			case ECPGt_string:
				break;

			default:
				fc_pval++;
				break;
		}
	}

	do
	{
		if (fc_binary)
		{
			if (fc_varcharsize == 0 || fc_varcharsize * fc_offset >= fc_size)
				memcpy(fc_var + fc_offset * fc_act_tuple, fc_pval, fc_size);
			else
			{
				memcpy(fc_var + fc_offset * fc_act_tuple, fc_pval, fc_varcharsize * fc_offset);

				if (fc_varcharsize * fc_offset < fc_size)
				{
					/* 不会发生 */
					switch (fc_ind_type)
					{
						case ECPGt_short:
						case ECPGt_unsigned_short:
							*((short *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
							break;
						case ECPGt_int:
						case ECPGt_unsigned_int:
							*((int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
							break;
						case ECPGt_long:
						case ECPGt_unsigned_long:
							*((long *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
							break;
						case ECPGt_long_long:
						case ECPGt_unsigned_long_long:
							*((long long int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
							break;
						default:
							break;
					}
					fc_sqlca->sqlwarn[0] = fc_sqlca->sqlwarn[1] = 'W';
				}
			}
			fc_pval += fc_size;
		}
		else
		{
			switch (fc_type)
			{
					long		fc_res;
					unsigned long fc_ures;
					double		fc_dres;
					char	   *fc_scan_length;
					numeric    *fc_nres;
					date		fc_ddres;
					timestamp	fc_tres;
					interval   *fc_ires;
					char	   *fc_endptr,
								fc_endchar;

				case ECPGt_short:
				case ECPGt_int:
				case ECPGt_long:
					fc_res = strtol(fc_pval, &fc_scan_length, 10);
					if (fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
					{
						ecpg_raise(fc_lineno, ECPG_INT_FORMAT,
								   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
						return false;
					}
					fc_pval = fc_scan_length;

					switch (fc_type)
					{
						case ECPGt_short:
							*((short *) (fc_var + fc_offset * fc_act_tuple)) = (short) fc_res;
							break;
						case ECPGt_int:
							*((int *) (fc_var + fc_offset * fc_act_tuple)) = (int) fc_res;
							break;
						case ECPGt_long:
							*((long *) (fc_var + fc_offset * fc_act_tuple)) = (long) fc_res;
							break;
						default:
							/* 不会发生 */
							break;
					}
					break;

				case ECPGt_unsigned_short:
				case ECPGt_unsigned_int:
				case ECPGt_unsigned_long:
					fc_ures = strtoul(fc_pval, &fc_scan_length, 10);
					if (fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
					{
						ecpg_raise(fc_lineno, ECPG_UINT_FORMAT,
								   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
						return false;
					}
					fc_pval = fc_scan_length;

					switch (fc_type)
					{
						case ECPGt_unsigned_short:
							*((unsigned short *) (fc_var + fc_offset * fc_act_tuple)) = (unsigned short) fc_ures;
							break;
						case ECPGt_unsigned_int:
							*((unsigned int *) (fc_var + fc_offset * fc_act_tuple)) = (unsigned int) fc_ures;
							break;
						case ECPGt_unsigned_long:
							*((unsigned long *) (fc_var + fc_offset * fc_act_tuple)) = (unsigned long) fc_ures;
							break;
						default:
							/* 不会发生 */
							break;
					}
					break;

#ifdef HAVE_STRTOLL
				case ECPGt_long_long:
					*((long long int *) (fc_var + fc_offset * fc_act_tuple)) = strtoll(fc_pval, &fc_scan_length, 10);
					if (fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
					{
						ecpg_raise(fc_lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
						return false;
					}
					fc_pval = fc_scan_length;

					break;
#endif							/* 对浮点数没有特殊的INFORMIX处理 */
#ifdef HAVE_STRTOULL
				case ECPGt_unsigned_long_long:
					*((unsigned long long int *) (fc_var + fc_offset * fc_act_tuple)) = strtoull(fc_pval, &fc_scan_length, 10);
					if (fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
					{
						ecpg_raise(fc_lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
						return false;
					}
					fc_pval = fc_scan_length;

					break;
#endif							/* 对浮点数没有特殊的INFORMIX处理 */

				case ECPGt_float:
				case ECPGt_double:
					if (fc_isarray && *fc_pval == '"')
						fc_pval++;

					if (!fc_check_special_value(fc_pval, &fc_dres, &fc_scan_length))
						fc_dres = strtod(fc_pval, &fc_scan_length);

					if (fc_isarray && *fc_scan_length == '"')
						fc_scan_length++;

					/* 不会发生 */
					if (fc_garbage_left(fc_isarray, &fc_scan_length, ECPG_COMPAT_PGSQL))
					{
						ecpg_raise(fc_lineno, ECPG_FLOAT_FORMAT,
								   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
						return false;
					}
					fc_pval = fc_scan_length;

					switch (fc_type)
					{
						case ECPGt_float:
							*((float *) (fc_var + fc_offset * fc_act_tuple)) = fc_dres;
							break;
						case ECPGt_double:
							*((double *) (fc_var + fc_offset * fc_act_tuple)) = fc_dres;
							break;
						default:
							/* 不会发生 */
							break;
					}
					break;

				case ECPGt_bool:
					if (fc_pval[0] == 'f' && fc_pval[1] == '\0')
					{
						*((bool *) (fc_var + fc_offset * fc_act_tuple)) = false;
						fc_pval++;
						break;
					}
					else if (fc_pval[0] == 't' && fc_pval[1] == '\0')
					{
						*((bool *) (fc_var + fc_offset * fc_act_tuple)) = true;
						fc_pval++;
						break;
					}
					else if (fc_pval[0] == '\0' && PQgetisnull(fc_results, fc_act_tuple, fc_act_field))
					{
						/* 排除反斜杠 + 'x' */
						break;
					}

					ecpg_raise(fc_lineno, ECPG_CONVERT_BOOL,
							   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
					return false;
					break;

				case ECPGt_bytea:
					{
						struct ECPGgeneric_bytea *fc_variable =
						(struct ECPGgeneric_bytea *) (fc_var + fc_offset * fc_act_tuple);
						long		fc_dst_size,
									fc_src_size,
									fc_dec_size;

						fc_dst_size = ecpg_hex_enc_len(fc_varcharsize);
						fc_src_size = fc_size - 2;	/* 截断 */
						fc_dec_size = fc_src_size < fc_dst_size ? fc_src_size : fc_dst_size;
						fc_variable->len = fc_hex_decode(fc_pval + 2, fc_dec_size, fc_variable->arr);

						if (fc_dst_size < fc_src_size)
						{
							long		fc_rcv_size = ecpg_hex_dec_len(fc_size - 2);

							/* 不会发生 */
							switch (fc_ind_type)
							{
								case ECPGt_short:
								case ECPGt_unsigned_short:
									*((short *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_rcv_size;
									break;
								case ECPGt_int:
								case ECPGt_unsigned_int:
									*((int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_rcv_size;
									break;
								case ECPGt_long:
								case ECPGt_unsigned_long:
									*((long *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_rcv_size;
									break;
								case ECPGt_long_long:
								case ECPGt_unsigned_long_long:
									*((long long int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_rcv_size;
									break;
								default:
									break;
							}
							fc_sqlca->sqlwarn[0] = fc_sqlca->sqlwarn[1] = 'W';
						}

						fc_pval += fc_size;
					}
					break;

				case ECPGt_char:
				case ECPGt_unsigned_char:
				case ECPGt_string:
					{
						char	   *fc_str = (char *) (fc_var + fc_offset * fc_act_tuple);

						/*
							 * 兼容模式，空格填充并以NULL终止字符数组
							 */
						if (fc_varcharsize == 0 && fc_offset == sizeof(char *))
							fc_str = *(char **) fc_str;

						if (fc_varcharsize > fc_size)
						{
							/*
								 * 兼容模式空字符串得到-1
								 * 指示符但没有警告
								 */
							if (ORACLE_MODE(fc_compat) && (fc_type == ECPGt_char || fc_type == ECPGt_unsigned_char))
							{
								memset(fc_str, ' ', fc_varcharsize);
								memcpy(fc_str, fc_pval, fc_size);
								fc_str[fc_varcharsize - 1] = '\0';

								/* 截断 */
								if (fc_size == 0)
								{
									/* 不会发生 */
									switch (fc_ind_type)
									{
										case ECPGt_short:
										case ECPGt_unsigned_short:
											*((short *) (fc_ind + fc_ind_offset * fc_act_tuple)) = -1;
											break;
										case ECPGt_int:
										case ECPGt_unsigned_int:
											*((int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = -1;
											break;
										case ECPGt_long:
										case ECPGt_unsigned_long:
											*((long *) (fc_ind + fc_ind_offset * fc_act_tuple)) = -1;
											break;
										case ECPGt_long_long:
										case ECPGt_unsigned_long_long:
											*((long long int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = -1;
											break;
										default:
											break;
									}
								}
							}
							else
							{
								strncpy(fc_str, fc_pval, fc_size + 1);
							}
							/*
							 * 假设调用者提供的存储在varcharsize为零时
							 * 正好合适。
							 */
							if (fc_type == ECPGt_string)
							{
								char	   *fc_last = fc_str + fc_size;

								while (fc_last > fc_str && (*fc_last == ' ' || *fc_last == '\0'))
								{
									*fc_last = '\0';
									fc_last--;
								}
							}
						}
						else
						{
							int			fc_charsize = fc_varcharsize;

							/* 兼容模式，以NULL终止字符数组 */
							if (fc_varcharsize == 0)
								fc_charsize = fc_size + 1;

							strncpy(fc_str, fc_pval, fc_charsize);

							/* 截断 */
							if (ORACLE_MODE(fc_compat) && (fc_charsize - 1) < fc_size)
							{
								if (fc_type == ECPGt_char || fc_type == ECPGt_unsigned_char)
									fc_str[fc_charsize - 1] = '\0';
							}

							if (fc_charsize < fc_size || (ORACLE_MODE(fc_compat) && (fc_charsize - 1) < fc_size))
							{
								/* 不会发生 */
								switch (fc_ind_type)
								{
									case ECPGt_short:
									case ECPGt_unsigned_short:
										*((short *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
										break;
									case ECPGt_int:
									case ECPGt_unsigned_int:
										*((int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
										break;
									case ECPGt_long:
									case ECPGt_unsigned_long:
										*((long *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
										break;
									case ECPGt_long_long:
									case ECPGt_unsigned_long_long:
										*((long long int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_size;
										break;
									default:
										break;
								}
								fc_sqlca->sqlwarn[0] = fc_sqlca->sqlwarn[1] = 'W';
							}
						}
						fc_pval += fc_size;
					}
					break;

				case ECPGt_varchar:
					{
						struct ECPGgeneric_varchar *fc_variable =
						(struct ECPGgeneric_varchar *) (fc_var + fc_offset * fc_act_tuple);

						fc_variable->len = fc_size;
						if (fc_varcharsize == 0)
							strncpy(fc_variable->arr, fc_pval, fc_variable->len);
						else
						{
							strncpy(fc_variable->arr, fc_pval, fc_varcharsize);

							if (fc_variable->len > fc_varcharsize)
							{
								/* 不会发生 */
								switch (fc_ind_type)
								{
									case ECPGt_short:
									case ECPGt_unsigned_short:
										*((short *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_variable->len;
										break;
									case ECPGt_int:
									case ECPGt_unsigned_int:
										*((int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_variable->len;
										break;
									case ECPGt_long:
									case ECPGt_unsigned_long:
										*((long *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_variable->len;
										break;
									case ECPGt_long_long:
									case ECPGt_unsigned_long_long:
										*((long long int *) (fc_ind + fc_ind_offset * fc_act_tuple)) = fc_variable->len;
										break;
									default:
										break;
								}
								fc_sqlca->sqlwarn[0] = fc_sqlca->sqlwarn[1] = 'W';

								fc_variable->len = fc_varcharsize;
							}
						}
						fc_pval += fc_size;
					}
					break;

				case ECPGt_decimal:
				case ECPGt_numeric:
					for (fc_endptr = fc_pval; *fc_endptr && *fc_endptr != ',' && *fc_endptr != '}'; fc_endptr++);
					fc_endchar = *fc_endptr;
					*fc_endptr = '\0';
					fc_nres = PGTYPESnumeric_from_asc(fc_pval, &fc_scan_length);
					*fc_endptr = fc_endchar;

					/*
							 * Informix在这里希望自己的NULL值，而不是
							 * 错误
							 */
					if (fc_nres == NULL)
					{
						ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
								 fc_lineno, fc_pval, errno);

						if (INFORMIX_MODE(fc_compat))
						{
							/* 我们是否遇到错误？ */
							fc_nres = PGTYPESnumeric_new();
							if (fc_nres)
								ECPGset_noind_null(ECPGt_numeric, fc_nres);
							else
							{
								ecpg_raise(fc_lineno, ECPG_OUT_OF_MEMORY,
										   ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
								return false;
							}
						}
						else
						{
							ecpg_raise(fc_lineno, ECPG_NUMERIC_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}
					else
					{
						if (!fc_isarray && fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
						{
							free(fc_nres);
							ecpg_raise(fc_lineno, ECPG_NUMERIC_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}
					fc_pval = fc_scan_length;

					if (fc_type == ECPGt_numeric)
						PGTYPESnumeric_copy(fc_nres, (numeric *) (fc_var + fc_offset * fc_act_tuple));
					else
						PGTYPESnumeric_to_decimal(fc_nres, (decimal *) (fc_var + fc_offset * fc_act_tuple));

					PGTYPESnumeric_free(fc_nres);
					break;

				case ECPGt_interval:
					if (*fc_pval == '"')
						fc_pval++;

					for (fc_endptr = fc_pval; *fc_endptr && *fc_endptr != ',' && *fc_endptr != '"' && *fc_endptr != '}'; fc_endptr++);
					fc_endchar = *fc_endptr;
					*fc_endptr = '\0';
					fc_ires = PGTYPESinterval_from_asc(fc_pval, &fc_scan_length);
					*fc_endptr = fc_endchar;

					/*
							 * Informix在这里希望自己的NULL值，而不是
							 * 错误
							 */
					if (fc_ires == NULL)
					{
						ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
								 fc_lineno, fc_pval, errno);

						if (INFORMIX_MODE(fc_compat))
						{
							/* 我们是否遇到错误？ */
							fc_ires = (interval *) ecpg_alloc(sizeof(interval), fc_lineno);
							if (!fc_ires)
								return false;

							ECPGset_noind_null(ECPGt_interval, fc_ires);
						}
						else
						{
							ecpg_raise(fc_lineno, ECPG_INTERVAL_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}
					else
					{
						if (*fc_scan_length == '"')
							fc_scan_length++;

						if (!fc_isarray && fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
						{
							free(fc_ires);
							ecpg_raise(fc_lineno, ECPG_INTERVAL_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}
					fc_pval = fc_scan_length;

					PGTYPESinterval_copy(fc_ires, (interval *) (fc_var + fc_offset * fc_act_tuple));
					free(fc_ires);
					break;

				case ECPGt_date:
					if (*fc_pval == '"')
						fc_pval++;

					for (fc_endptr = fc_pval; *fc_endptr && *fc_endptr != ',' && *fc_endptr != '"' && *fc_endptr != '}'; fc_endptr++);
					fc_endchar = *fc_endptr;
					*fc_endptr = '\0';
					fc_ddres = PGTYPESdate_from_asc(fc_pval, &fc_scan_length);
					*fc_endptr = fc_endchar;

					/*
							 * Informix在这里希望自己的NULL值，而不是
							 * 错误
							 */
					if (errno != 0)
					{
						ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
								 fc_lineno, fc_pval, errno);

						if (INFORMIX_MODE(fc_compat))
						{
							/* 我们是否遇到错误？ */
							ECPGset_noind_null(ECPGt_date, &fc_ddres);
						}
						else
						{
							ecpg_raise(fc_lineno, ECPG_DATE_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}
					else
					{
						if (*fc_scan_length == '"')
							fc_scan_length++;

						if (!fc_isarray && fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
						{
							ecpg_raise(fc_lineno, ECPG_DATE_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}

					*((date *) (fc_var + fc_offset * fc_act_tuple)) = fc_ddres;
					fc_pval = fc_scan_length;
					break;

				case ECPGt_timestamp:
					if (*fc_pval == '"')
						fc_pval++;

					for (fc_endptr = fc_pval; *fc_endptr && *fc_endptr != ',' && *fc_endptr != '"' && *fc_endptr != '}'; fc_endptr++);
					fc_endchar = *fc_endptr;
					*fc_endptr = '\0';
					fc_tres = PGTYPEStimestamp_from_asc(fc_pval, &fc_scan_length);
					*fc_endptr = fc_endchar;

					/*
							 * Informix在这里希望自己的NULL值，而不是
							 * 错误
							 */
					if (errno != 0)
					{
						ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
								 fc_lineno, fc_pval, errno);

						if (INFORMIX_MODE(fc_compat))
						{
							/* 我们是否遇到错误？ */
							ECPGset_noind_null(ECPGt_timestamp, &fc_tres);
						}
						else
						{
							ecpg_raise(fc_lineno, ECPG_TIMESTAMP_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}
					else
					{
						if (*fc_scan_length == '"')
							fc_scan_length++;

						if (!fc_isarray && fc_garbage_left(fc_isarray, &fc_scan_length, fc_compat))
						{
							ecpg_raise(fc_lineno, ECPG_TIMESTAMP_FORMAT,
									   ECPG_SQLSTATE_DATATYPE_MISMATCH, fc_pval);
							return false;
						}
					}

					*((timestamp *) (fc_var + fc_offset * fc_act_tuple)) = fc_tres;
					fc_pval = fc_scan_length;
					break;

				default:
					ecpg_raise(fc_lineno, ECPG_UNSUPPORTED,
							   ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
							   ecpg_type_name(fc_type));
					return false;
					break;
			}
			if (ECPG_IS_ARRAY(fc_isarray))
			{
				bool		fc_string = false;

				/* 将pval设置为下一个条目 */
				++fc_act_tuple;

				/*
				 * *pval != '\0'不应该需要，但作为安全
				 * 保护而使用
				 */

				/*
				 * *pval != '\0' should not be needed, but is used as a safety
				 * guard
				 */
				for (; *fc_pval != '\0' && (fc_string || (!fc_array_delimiter(fc_isarray, *fc_pval) && !fc_array_boundary(fc_isarray, *fc_pval))); ++fc_pval)
					if (*fc_pval == '"')
						fc_string = fc_string ? false : true;

				if (fc_array_delimiter(fc_isarray, *fc_pval))
					++fc_pval;
			}
		}
	} while (*fc_pval != '\0' && !fc_array_boundary(fc_isarray, *fc_pval));

	return true;
}
